package com.chen.authority.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.authority.common.constant.SysConstant;
import com.chen.authority.common.response.Response;
import com.chen.authority.common.util.TreeUtil;
import com.chen.authority.common.util.WrapperUtil;
import com.chen.authority.mapper.DepartmentMapper;
import com.chen.authority.mapper.UserMapper;
import com.chen.authority.model.dto.DepartmentDto;
import com.chen.authority.model.po.DepartmentPo;
import com.chen.authority.model.po.UserPo;
import com.chen.authority.model.qo.DepartmentQo;
import com.chen.authority.model.vo.DepartmentVo;
import com.chen.authority.service.DepartmentService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 部门Service业务层处理
 *
 * @author chengy
 * @date 2022-08-19
 */
@Service
@RequiredArgsConstructor
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, DepartmentPo> implements DepartmentService {

    private final UserMapper userMapper;

    @Override
    public Response addOrUpdateDepartment(Integer id, DepartmentDto dto) {
        DepartmentPo fatherDepartment = baseMapper.selectById(dto.getParentId());
        boolean hasFatherDepartment = ObjectUtil.isNotNull(fatherDepartment);
        boolean hasId = ObjectUtil.isNotNull(id);

        if (hasFatherDepartment) {
            Integer type = fatherDepartment.getType();
            if (type != SysConstant.HEAD_OFFICE && checkDepartmentStructureCorrect(dto.getType(), type)) {
                return Response.fail("部门层级有误，请注意父类部门的选择");
            }
            boolean exists = baseMapper.exists(Wrappers.<DepartmentPo>lambdaQuery()
                    .eq(DepartmentPo::getName, dto.getName())
                    .eq(DepartmentPo::getParentId, dto.getParentId())
                    .ne(hasId, DepartmentPo::getId, id));
            if (exists) return Response.fail("部门名称重复，请检查");
        }

        DepartmentPo department = dto.toPo(DepartmentPo.class);

        if (hasId) {
            if (dto.getStatus() == SysConstant.DISABLE && checkDeptHasSubDeptOrUser(id)) {
                return Response.fail("该部门下拥有子部门或员工，无法删除");
            }
            department.setId(id);
        } else {
            baseMapper.insert(department);
        }

        if (hasFatherDepartment) {
            department.setAncestors(fatherDepartment.getAncestors() + StrUtil.COMMA + department.getId());
        }

        return this.saveOrUpdate(department) ? Response.success() : Response.fail();
    }

    @Override
    public Response deleteDepartmentById(Integer id) {
        if (checkDeptHasSubDeptOrUser(id)) {
            return Response.fail("该部门下拥有子部门或员工，无法删除");
        }
        return this.removeById(id) ? Response.success() : Response.fail();
    }

    @Override
    public List<DepartmentVo> findDepartmentsByCondition(DepartmentQo qo) {
        LambdaQueryWrapper<DepartmentPo> lqw = WrapperUtil.buildLambdaQueryWrapper(qo);
        boolean emptyOfNormal = lqw.isEmptyOfNormal();
        lqw.orderByAsc(DepartmentPo::getParentId).orderByAsc(DepartmentPo::getSort);
        List<DepartmentVo> departments = baseMapper.selectVoList(lqw);
        if (emptyOfNormal) {
            departments = TreeUtil.build(SysConstant.ROOT, departments);
        } else if (CollUtil.isNotEmpty(departments)) {
            List<DepartmentVo> departmentList = new ArrayList<>(departments);
            TreeUtil.removeSubNodes(departments);
            departments = TreeUtil.build(departments, departmentList);
        }
        return departments;
    }

    private boolean checkDeptHasSubDeptOrUser(Integer id) {
        boolean exists = baseMapper.exists(Wrappers
                .<DepartmentPo>lambdaQuery()
                .eq(DepartmentPo::getParentId, id));
        if (exists) return true;
        exists = userMapper.exists(Wrappers
                .<UserPo>lambdaQuery()
                .eq(UserPo::getDepartmentId, id));
        return exists;
    }

    private boolean checkDepartmentStructureCorrect(Integer childrenType, Integer parentType) {
        switch (childrenType) {
            case SysConstant.BRANCH_OFFICE:
                return parentType != SysConstant.HEAD_OFFICE;
            case SysConstant.DEPARTMENT:
                return parentType != SysConstant.BRANCH_OFFICE;
            default:
                return true;
        }
    }

}